#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <stdexcept>

using std::cin;
using std::cout;
using std::endl;
using std::exception;
using std::invalid_argument;
using std::mutex;
using std::string;
using std::thread;
using std::vector;

namespace bzh
{
    struct ListNode
    {
        // std::shared_ptr<ListNode> _next;
        // std::shared_ptr<ListNode> _prve;
        //  可以指向资源/访问资源，不参与资源管理，不增加引用计数
        std::weak_ptr<ListNode> _next;
        std::weak_ptr<ListNode> _prve;
        int _val;
        ~ListNode()
        {
            cout << "delete node" << endl;
        }
    };

    template <class T>
    class default_delete // 默认删除器
    {
    public:
        void operator()(T *ptr)
        {
            delete ptr;
        }
    };

    template <class T, class D = default_delete<T>>
    class shared_ptr
    {
    public:
        shared_ptr(T *ptr = nullptr) // 默认构造
            : _ptr(ptr), _pcount(new int(1)), _pmtx(new mutex)
        {
        }

        ~shared_ptr()
        {
            Release();
        }

        shared_ptr(const shared_ptr<T> &sp)
            : _ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx)
        {
            _pmtx->lock();
            ++(*_pcount);
            _pmtx->unlock();
        }

        void Release()
        {
            bool flag = false;
            _pmtx->lock();
            if (--(*_pcount) == 0)
            {
                delete _pcount;
                // delete _ptr;
                // 定制删除器来删除
                _del(_ptr); // 不传删除器就用默认的
                flag = true;
            }
            _pmtx->unlock();
            if (flag == true)
                delete _pmtx;
        }

        shared_ptr<T> &operator=(const shared_ptr<T> &sp)
        {
            if (_ptr != sp._ptr)
            {
                Release();

                _pcount = sp._pcount;
                _ptr = sp._ptr;
                _pmtx = sp._pmtx;

                _pmtx->lock();
                ++(*_pcount);
                _pmtx->unlock();
            }
            return *this;
        }

        int use_count()
        {
            return *_pcount;
        }

        T *get() const
        {
            return _ptr;
        }

        T &operator*()
        {
            return *_ptr;
        }

        T *operator->()
        {
            return _ptr;
        }

        T &operator[](size_t pos)
        {
            return _ptr[pos];
        }

    private:
        T *_ptr;
        int *_pcount; // 堆区开辟引用计数
        mutex *_pmtx; // 堆区开辟锁空间

        D _del; // 定制删除器
    };

    // 定制删除器 --- 释放/销毁方式不对就会崩
    template <class T>
    struct DeleteArray
    {
        void operator()(const T *ptr)
        {
            delete[] ptr;
            cout << "delete [] " << ptr << endl;
        }
    };

    struct Fclose
    {
        void operator()(FILE *ptr)
        {
            fclose(ptr);
        }
    };
    void test_shared_ptr3()
    {
        // std::shared_ptr<int> sp1(new int[10], DeleteArray<int>());
        // std::shared_ptr<string> sp2(new string[10], DeleteArray<string>());
        // 我们自己实现的定制删除器，不能够直接在构造函数传,我们在类的参数去传
        bzh::shared_ptr<ListNode> n1(new ListNode);                            // 默认删除器
        bzh::shared_ptr<ListNode, DeleteArray<ListNode>> n2(new ListNode[10]); // 在模板那里传
        //////------ 先打印10个delete node 然后打印delete [] 0x...... 最后再打印一次delete node 因为先构造n1，再构造n2，析构反着来------//////

        // 这里我们的用lambda不行，lambda是一个匿名对象，而这里我们要传类型
        //  decltype是运行时的类型推到，我们要编译时就要拿到类型
        // bzh::shared_ptr<FILE, decltype([](FILE* ptr){fclose(ptr); })> n2(fopen("Test.cpp", "r"));

        // bzh::shared_ptr<FILE, Fclose> n3(fopen("Test.cpp", "r")); // 不传Fclose就是使用delete，就会崩

        /*std::unique_ptr<FILE, decltype([](FILE* ptr){fclose(ptr); })> up3(fopen("Test.cpp", "r"));*/

        // std::unique_ptr<FILE, Fclose> up3(fopen("Test.cpp", "r"));
    }
}
int main()
{
    bzh::test_shared_ptr3();
    return 0;
}

// template <class T>
// class SmartPtr
// {
// public:
//     /// RAII —— 资源获得即初始化
//     SmartPtr(T *ptr)
//         : _ptr(ptr)
//     {
//     }
//     ~SmartPtr()
//     {
//         delete[] _ptr;
//         cout << "delete ptr" << endl;
//     }
//     ///

//     /// 像指针一样
//     T &operator*()
//     {
//         return *_ptr;
//     }
//     T *operator->()
//     {
//         return _ptr;
//     }
//     T &operator[](size_t pos)
//     {
//         return _ptr[pos];
//     }

// private:
//     T *_ptr;
// };

// int div()
// {
//     int a, b;
//     cin >> a >> b;
//     if (b == 0)
//         throw invalid_argument("除0错误");
//     return a / b;
// }

// void Func()
// {
//     SmartPtr<int> sp1(new int[10]);
//     SmartPtr<int> sp2(new int[10]);
//     *sp1 = 10;
//     sp1[0]--;
//     cout << *sp1 << endl;
//     cout << div() << endl;
// }

// int main()
// {
//     try
//     {
//         Func();
//     }
//     catch (exception &e)
//     {
//         cout << e.what() << endl;
//     }
//     return 0;
// }

// namespace bzh
// {
//     template <class T>
//     class shared_ptr
//     {
//     public:
//         // RAII
//         // 保存资源
//         shared_ptr(T *ptr = nullptr)         // 默认构造
//             : _ptr(ptr), _pcount(new int(1)) // 初始值就要为1
//               ,
//               _pmtx(new mutex)
//         {
//         }
//         // 释放资源
//         ~shared_ptr()
//         {
//             Release();
//         }
//         shared_ptr(const shared_ptr<T> &sp)                       // 拷贝构造，浅拷贝
//             : _ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx) // 这个时候拷贝，就是拷贝锁的指针了
//         {
//             _pmtx->lock(); // 加锁 —— 多个线程同时执行++操作时，只有一个线程能够执行成功
//             ++(*_pcount);
//             _pmtx->unlock(); // 解锁
//         }
//         void Release()
//         {
//             bool flag = false; // flag是局部变量，有独立的栈结构，互相不影响
//             _pmtx->lock();
//             if (--(*_pcount) == 0)
//             {
//                 delete _pcount; // 这些变量都是堆上面的，堆区的数据是共享的
//                 delete _ptr;
//                 flag = true;
//             }
//             _pmtx->unlock();
//             if (flag == true)
//                 delete _pmtx;
//         }

//         // sp1 = sp1;
//         // sp1 = sp2;
//         shared_ptr<T> &operator=(const shared_ptr<T> &sp)
//         {
//             if (_ptr != sp._ptr)
//             {
//                 Release(); // 先判断计数，减了计数等于0，就表示是最后一个指针，就要释放了

//                 _pcount = sp._pcount;
//                 _ptr = sp._ptr;
//                 _pmtx = sp._pmtx;

//                 _pmtx->lock();
//                 ++(*_pcount);
//                 _pmtx->unlock();
//             }
//             return *this;
//         }

//         int use_count()
//         {
//             return *_pcount;
//         }

//         T *get() const
//         {
//             return _ptr;
//         }

//         // 像指针一样
//         T &operator*()
//         {
//             return *_ptr;
//         }
//         T *operator->()
//         {
//             return _ptr;
//         }
//         T &operator[](size_t pos)
//         {
//             return _ptr[pos];
//         }

//     private:
//         T *_ptr;
//         int *_pcount;
//         // 这里的锁只保护引用计数的安全，智能指针指向的资源空间安全不保护！！ int *_pcount; // 堆区开辟引用计数
//         mutex *_pmtx; // 堆区开辟锁空间
//     };

//     void test_shared_ptr() // 两个线程对智能指针sp1疯狂拷贝，析构
//     {
//         int n = 10000;
//         shared_ptr<int> sp1(new int(1));
//         thread t1(
//             [&]() mutable -> void
//             {
//                 for (size_t i = 0; i < n; ++i)
//                     shared_ptr<int> sp2(sp1);
//             });
//         thread t2(
//             [&]() mutable -> void
//             {
//                 for (size_t j = 0; j < n; ++j)
//                     shared_ptr<int> sp3(sp1);
//             });
//         t1.join();
//         t2.join();

//         cout << sp1.use_count() << endl;
//         cout << sp1.get() << endl;
//     }
// }
// int main()
// {
//     bzh::test_shared_ptr();
//     return 0;
// }
